html 歌词同步滚动实现思路深入解析

您所在的位置:网站首页 Audio组件 歌词 html 歌词同步滚动实现思路深入解析

html 歌词同步滚动实现思路深入解析

2024-06-04 07:18| 来源: 网络整理| 查看: 265

效果展示

跟随歌曲时间同步滚动歌词,并实现高亮效果

自动播放

改变进度 总体思路 获取歌词 解析歌词 打印歌词 同步歌词 1. 获取歌词

用 ajax 和网易云的 api 获取的歌词资源.(涉及到跨域问题,这里不赘述,主要讲同步功能的思路)

2. 解析歌词

步骤: 1. 新建数组 lrcArray 2. 提取歌词 lrcGet 3. 用换行符把字符串 lrcGet分 割为数组 lrc 4. 遍历 lrc

其中,遍历 lrc 后的处理步骤

过滤 提取和转化时间 提取歌词 添加进数组 lrcArray

控制台返回的 lrcGet

lrc

js

var lrcArray = [];//新建数组,用于存放歌词 var lrcGet = data.lrc.lyric;//提取歌词 // console.log(lrcGet); var lrc = lrcGet.split('\n'); // console.log(lrc); $.each(lrc, function(i, item) { //过滤空白文本 if (item.split(']')[1] == "" || item == "" || item.indexOf('作曲') !== -1 || item.indexOf('作词') !== -1) { return true; } //转化时间 var timeStr = item.substring(item.indexOf("[") + 1, item.indexOf("]")); var min = parseInt(timeStr.split(':')[0]) * 60; var sec = parseFloat(timeStr.split(':')[1]); var time = parseFloat((min + sec).toFixed(2)); //添加进数组 lrcArray.push({ t: time, c: item.substring(item.indexOf(']') + 1) }); }); 3. 打印歌词

控制台返回处理后的数组lrcArray如下:

html代码

js

//显示歌词 //打印全部在页面 var html = ""; $.each(lrcArray, function(i, v) { html += '' + v.c + ''; }); $('.lyricsList').append(html); 4. 同步歌词 $('#audio')[0].ontimeupdate = function() { $.each(lrcArray, function(i, v) { if ($('#audio')[0].currentTime >= lrcArray[i].t) { $('.lyricsList').css('margin-top', '');//避免进度变动时数值产生混乱 $('.lyricsList li').eq(i).addClass('highlight'); $('.lyricsList li').eq(i).siblings().removeClass('highlight'); if (i > 2) { $('.lyricsList').css('margin-top', (-i + 2) * 30 + 'px'); } } }); };

思路: audio 时间进度每更新一次,就同步一次该数组,把audio 的当前时间和数组每一项的时间作比较.当检测到前者大于或等于后者,就高亮和滚动对应的歌词.

关于高亮的思路 以代码的角度:

以index(这里对应 i)为桥梁,只要符合条件,对应的 li 就会先被高亮后被消除高亮,一直到最后一个符合条件的 lrcArray[i].t里的 i对应的 li被高亮,此时只会高亮而不会消除,等到 i+1 符合条件,i 的 先高亮后消除,i+1只高亮,以此迭代下去.

从样式上看:

由于代码执行飞速,以致肉眼不会看到先高亮后消除的过程,只会看到最后一个被高亮.

关于滚动的思路

从第一行歌词开始滚动,定格在第三行

html代码

css 样式

.lyrics { height: 32%; padding-top: 8px; overflow: hidden; } .lyrics .lyricsList { margin: 0; padding: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; } .lyrics .lyricsList li { height: 30px; line-height: 15px; font-size: 12px; }

js 代码

var index = 0; $('#audio')[0].ontimeupdate = function() { if (this.currentTime >= parseFloat(lrcArray[index].t)) { $('.lyricsList li').eq(index).addClass('highlight'); $('.lyricsList li').eq(index).siblings().removeClass('highlight'); if (index > 2) { //添加 css 样式以实现滚动效果 $('.lyricsList').css('margin-top', -(index - 2) * 30 + 'px'); } index++; } };

js 滚动思路分析图

从 i>2 起设置margin-top负值. 当滚动到 i=3对应的 li 节点后,margin-top 的值每次增加一个负的 li 的行高,即-30px,以实现推动效果。在高亮效果滚动到下一个 li的同时,ul 容器往上推动一个li行高,两者作用下的效果为高亮位置保持不变。

注:

在条件代码块的第一行用.css('margin-top', '')消除样式,避免每一次margin-top 值发生改变引起数值错乱,避免 bug.

以下在触发进度条事件时,会发生同步错误. 原因: 当this.currentTime突然变小,而 index 无法随之改变,因此条件无法匹配. 当this.currentTime突然变大, index也无法突变,只能递增,会产生逐行高亮又消失,直到匹配到临界值的情况.

涉及的 jq 方法总结 dom 方法 $(dom).eq(i) 返回第i 个; $(dom).siblings() dom的兄弟节点,即除了自己,借助该方法可实现兄弟节点之前的排他性样式,如歌词高亮. $(dom).empty() 清空所有子节点 $(dom).css('属性', ''); 消除某个属性 each遍历中跳出循环的方法: return false;——跳出所有循环;相当于 javascript 中的 break 效果。 return true;——跳出当前循环,进入下一个循环;相当于 javascript 中的 continue 效果 过滤空白文本和包含关键词文本 if (item.split(']')[1] == "" || item == "" || item.indexOf('作曲') !== -1 || item.indexOf('作词') !== -1) { return true; 字符串 str.split('\n') str.substring(str.indexOf("[") + 1, str.indexOf("]")) 提取[]中间的字符串 str.indexOf(str,str) 数字 str.parseInt(),str.parseFloat() num.toFixed(num) 数组 arr.push(item) 完整代码 .lyrics { height: 32%; padding-top: 8px; overflow: hidden; } .lyrics .lyricsList { margin: 0; padding: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; } .lyrics .lyricsList li { height: 30px; line-height: 15px; font-size: 12px; } //歌词高亮 .highlight { color: #3effee; text-shadow: 0 0 10px #ded1fc; } function parseLrc(data) { // console.log(data); var lrcArray = []; //新建数组,用于存放歌词 var lrcGet = data.lrc.lyric; //提取歌词 console.log(lrcGet); var lrc = lrcGet.split('\n'); console.log(lrc); $.each(lrc, function(i, item) { //过滤空白文本 if (item.split(']')[1] == "" || item == "" || item.indexOf('作曲') !== -1 || item.indexOf('作词') !== -1) { return true; } //转化时间 var timeStr = item.substring(item.indexOf("[") + 1, item.indexOf("]")); var min = parseInt(timeStr.split(':')[0]) * 60; var sec = parseFloat(timeStr.split(':')[1]); var time = parseFloat((min + sec).toFixed(2)); //添加进数组 lrcArray.push({ t: time, c: item.substring(item.indexOf(']') + 1) }); }); console.log(lrcArray); //显示歌词 var html = ""; $.each(lrcArray, function(i, v) { html += '' + v.c + ''; }); $('.lyricsList').append(html); //同步高亮歌词 $('#audio')[0].ontimeupdate = function() { $.each(lrcArray, function(i, v) { if ($('#audio')[0].currentTime >= lrcArray[i].t) { $('.lyricsList').css('margin-top', ''); $('.lyricsList li').eq(i).addClass('highlight'); $('.lyricsList li').eq(i).siblings().removeClass('highlight'); if (i > 2) { $('.lyricsList').css('margin-top', (-i + 2) * 30 + 'px'); } } }); }; }

本文作者: 乔一亖 本文链接: https://www.cnblogs.com/joyce33/p/13376752.html 版权声明: 本文版权归作者和博客园共有,转载请注明出处!如有问题或建议,请多多赐教,非常感谢。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3